'''
NurbsCad
Archivo cono, modulo de NurbsCad
Autor: Gustavo Enrique Bellino
Contacto: gushbellino@gmail.com
Fecha: Junio de 2009
Descripcion: clase Cono para manipular un cono.
Licencia: GNU Public License version 2
'''

from __future__ import division
import os, sys, math

#Se agrega al path la carpeta ../
modulesdir = os.path.abspath(os.path.join(os.path.dirname(__file__), '../'))
sys.path.insert(0, modulesdir)

#librerias de un nivel superior
from library import *
from nurbSurface import NurbSurface

class Cono(Library):
    def __init__(self, identifier, escena, parameters):
        #Asociacion de Parametros
        
        #Si esta variable no esta seteada en True el objeto no puede agregarse a la escena.
        self.success = True
        punto1 = parameters[0]
        xyz = punto1.split(',') #realizar expresion regular aqui.
        punto1x = float(xyz[0])
        punto1y = float(xyz[1])
        punto1z = float(xyz[2])
        self.punto1 = Vector3(punto1x, punto1y, punto1z)
        
        punto2 = parameters[1]
        xyz = punto2.split(',') #realizar expresion regular aqui.
        punto2x = float(xyz[0])
        punto2y = float(xyz[1])
        punto2z = float(xyz[2])
        self.punto2 = Vector3(punto2x, punto2y, punto2z)
        
        self.radio1 = parameters[2]
        self.radio2 = parameters[3]
        name = parameters[4]
        
        self.pto_de_ctrol = []
        self.nurbs_base_created = False
        self.nurbs_top_created = False
        
        self.visible = True
        self.escena = escena
        
        #Identificador
        self.identifier = identifier
        
        #Variable para que la Escena elimine el objeto de su lista de objetos, variable que indica la seleccion del objeto
        self.autoEliminate = False
        self.bSelected = False
        
        #Tipo, nombre y colores del objeto
        self.type = 'Cono'
        self.name = name
        self.color = (0, 0, 1, 0)
        self.colorSelected = (1, 0, 0, 0)
        
        #Inicializa los puntos para dibujar el cono
        #self.inicialice()
        return 

    def getClassName():
        return 'Cono'
    getClassName = staticmethod(getClassName)

    def getNameInMenu():
        return 'Cono'
    getNameInMenu = staticmethod(getNameInMenu)

    def getParametersForCreate():
        title = 'Ingrese los parametros indicados para crear un cono:'
        parameters = [title, 
                      ('Punto1 (x,y,z)', str), 
                      ('Punto2 (x,y,z)', str), 
                      ('Radio 1', float), 
                      ('Radio 2', float), 
                      ('Nombre', str)
                      ]
        return parameters
    getParametersForCreate = staticmethod(getParametersForCreate)

    def inicialice(self):
        '''Inicializa los Puntos de referencia del Frustum'''
        return


    def draw(self, selectMode=False):
        '''Callback Display del objeto'''
        if(not selectMode):
            color = self.color
            if(self.bSelected):
                color = self.colorSelected
        else:
            inc = (1.0/255)
            red = (inc) * self.identifier
            color = (red, red, red,  0)
        
        width = 2
        if(self.visible):
            self.drawPoligon([self.punto1, self.punto2], color, width)
            #Punto de referencia
            radius = 0.1
            slices = 10
            stacks = 10
            self.draw_sphere(self.punto1,  radius, slices, stacks, color)
            self.draw_sphere(self.punto2,  radius, slices, stacks, color)
        
#        if self.nurbs_base_created:
#            self.nurbs_base.draw()
#        if self.pto_de_ctrol.__len__() >= 1:
#            for p in self.pto_de_ctrol:
#                #Punto de referencia
#                radius = 0.05
#                slices = 10
#                stacks = 10
#                color = (0, 0, 1, 0)
#                self.draw_sphere(p,  radius, slices, stacks, color)
#        for p in self.pto_de_ctrol:
#            self.draw_line(p, self.punto1)
        return 0


    def drawPoligon(self, pointsList, color, width):
        '''Dibuja un poligono con los puntos que se le pasa por parametro en forma de lista '''
        cero = pointsList[0]
        for p in pointsList:
            self.draw_line(cero, p, color, width)
            cero = p


    def Mouse(self, x, y, camara, plano):
        '''CallBack Mouse'''
        #Identifica si un punto de control fue seleccionado
        tolerance = 0.1
        pos = self.convertTo3D(x, y)
        recta = [camara.eyes, pos]
        tolerance = 0.1
        for p in [self.punto1, self.punto2]:
            if(p.distFromRect(recta)<tolerance):
                plano.desplazar(p)
                self.selectedPoint = p
        self.setPoints()
        self.escena.queue_draw()
        return 0

    def Motion(self, x, y, width, heigth, camara, plano):
        '''CallBack Motion'''
        #se edita todos los puntos seleccionados
        pos = self.convertTo3D(x, y)
        recta = [camara.eyes, pos]
        puntoNuevo = plano.interseccion(recta)
        
        plano.desplazar(puntoNuevo)
        desp = puntoNuevo - self.selectedPoint
        
        self.selectedPoint += desp
        self.setPoints()
        return 0

    def actionsToDo(self):
        '''Acciones del objeto'''
        verCono = '01-Mostrar Cono'
        if(self.visible):
            verCono = '01-Ocultar Cono'
        self.actions = {'01-cono/visible.png': (lambda x: self.setPoints(), 'Visualizar cono')}
        return self.actions.keys()
    
    def setPoints(self):
        self.pto_de_ctrol = []
        vect = self.punto2 - self.punto1
        
        perp1 = Vector3(1, 0, 0).cross(vect).normalize()
        if perp1.module()<0.1:
            perp1 = Vector3(0, 1, 0).cross(vect).normalize()
        perp2 = perp1.cross(vect).normalize()
        
        perp1 *= self.radio1
        perp2 *= self.radio1
        perp3 = (perp1 - perp2)/2
        perp4 = (perp2 - (-perp1))/2
        
        vect = self.punto1
        p1 = perp3 + vect
        p2 = -perp2 + vect
        p3 = -perp4 + vect
        p4 = -perp1 + vect
        p5 = -perp3 + vect
        p6 = perp2 + vect
        p7 = perp4 + vect
        p8 = perp1 + vect
        
        dif = self.radio2 / self.radio1
        vect = self.punto2 - self.punto1
        p1_2 = ((p1 + vect) - self.punto2) * dif + self.punto2
        p2_2 = ((p2 + vect) - self.punto2) * dif + self.punto2
        p3_2 = ((p3 + vect) - self.punto2) * dif + self.punto2
        p4_2 = ((p4 + vect) - self.punto2) * dif + self.punto2
        p5_2 = ((p5 + vect) - self.punto2) * dif + self.punto2
        p6_2 = ((p6 + vect) - self.punto2) * dif + self.punto2
        p7_2 = ((p7 + vect) - self.punto2) * dif + self.punto2
        p8_2 = ((p8 + vect) - self.punto2) * dif + self.punto2
        
        self.pto_de_ctrol.append(p1)
        self.pto_de_ctrol.append(p1_2)
        self.pto_de_ctrol.append(p2)
        self.pto_de_ctrol.append(p2_2)
        self.pto_de_ctrol.append(p3)
        self.pto_de_ctrol.append(p3_2)
        self.pto_de_ctrol.append(p4)
        self.pto_de_ctrol.append(p4_2)
        self.pto_de_ctrol.append(p5)
        self.pto_de_ctrol.append(p5_2)
        self.pto_de_ctrol.append(p6)
        self.pto_de_ctrol.append(p6_2)
        self.pto_de_ctrol.append(p7)
        self.pto_de_ctrol.append(p7_2)
        self.pto_de_ctrol.append(p8)
        self.pto_de_ctrol.append(p8_2)
        self.pto_de_ctrol.append(p1)
        self.pto_de_ctrol.append(p1_2)
        
        if not self.nurbs_base_created:
            id = 0
            id = self.escena.getNextIdentifier()
            self.nurbs_base = NurbSurface(id, self.escena, [9, 2])
            self.nurbs_base.setCtrlPoints(self.pto_de_ctrol)
            self.nurbs_base_created = True
            self.nurbs_base.visiblePoints = False
            self.nurbs_base.visiblePoligon = False
            self.nurbs_base.knotsU = [0,  0,  0,  0.25,  0.25,  0.5,  0.5,  0.75,  0.75, 1, 1, 1 ]
            self.nurbs_base.knotsV = [0,  0,  1,  1]
            self.nurbs_base.ordenU = 3
            self.nurbs_base.ordenV = 2
            self.escena.addObject(self.nurbs_base)
        else:
            self.nurbs_base.iniciado = False
            self.nurbs_base.setCtrlPoints(self.pto_de_ctrol)
        
        self.escena.queue_draw()

    def setVisible(self):
        '''Cambia el estado de la variable de visualizacion del Frustum'''
        self.visibleFrustum = not self.visibleFrustum
        return
    
    def atributesToEdit(self):
        '''Atributos para editar'''
        self.atributes = {
        'Radio 1': (self.getRadio(1), lambda spinner1:self.setRadio(1, spinner1)), 
        'Radio 2': (self.getRadio(2), lambda spinner1:self.setRadio(2, spinner1))}
        return self.atributes
    
    def getRadio(self, which_one):
        if which_one == 1:
            return self.radio1
        else:
            return self.radio2

    def setRadio(self, which_one, spinbutton_widget):
        valor = spinbutton_widget.get_value()
        if abs(valor) < 0.1:
            valor = 0.1
        if which_one == 1:
            self.radio1 = valor
        else:
            self.radio2 = valor
        self.setPoints()
        self.escena.queue_draw()
